package fun.ticsmyc.rpc.common.serializer.impl;


import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import fun.ticsmyc.rpc.common.entity.RpcRequest;
import fun.ticsmyc.rpc.common.serializer.SerializerCode;
import fun.ticsmyc.rpc.common.exception.SerializeException;
import fun.ticsmyc.rpc.common.serializer.Serializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

/**
 * 使用JackSon实现的json序列化器
 *      基于 JSON 的序列化器有一个毛病，就是在某个类的属性反序列化时，
 *      如果属性声明为 Object 的，就会造成反序列化出错，
 *      通常会把 Object 属性直接反序列化成 String 类型，就需要其他参数辅助序列化
 *
 * 【JSON编码 数据冗长，转码性能一般】
 * @author Ticsmyc
 * @date 2020-10-26 11:00
 */
public class JsonSerializer implements Serializer {
    public final byte ID = SerializerCode.JSON.getCode();
    private static Logger logger = LoggerFactory.getLogger(JsonSerializer.class);

    private static ObjectMapper objectMapper=null;

    private volatile static JsonSerializer INSTANCE=null;

    private JsonSerializer(){}
    public static JsonSerializer getInstance(){
        if(INSTANCE ==null){
            synchronized (JsonSerializer.class){
                if(INSTANCE == null){
                    INSTANCE = new JsonSerializer();
                    objectMapper = new ObjectMapper();
                }
            }
        }
        return INSTANCE;
    }

    @Override
    public byte[] serialize(Object obj) {
        if(obj == null){
            logger.error("试图对空对象执行序列化操作");
            throw new SerializeException("试图序列化一个null对象");
        }
        try {
            return objectMapper.writeValueAsBytes(obj);
        } catch (JsonProcessingException e) {
            logger.error("序列化时发生错误:",e);
            throw new SerializeException("序列化时有错误发生");
        }
    }

    @Override
    public Object deserialize(byte[] bytes, Class<?> clazz) {
        if(bytes == null || bytes.length<1){
            logger.error("试图对空字节数组进行反序列化");
            throw new SerializeException("试图对空字节数组进行反序列化");
        }
        try {
            Object obj = objectMapper.readValue(bytes, clazz);
            if(obj instanceof RpcRequest){
                //处理
                obj = handleRequest(obj);
            }
            return obj;
        } catch (IOException e) {
            logger.error("反序列化时发生错误:",e);
            throw new SerializeException("反序列化时有错误发生");
        }
    }

    @Override
    public byte getId() {
        return ID;
    }

    /**
     * 这里由于使用JSON序列化和反序列化Object数组，无法保证反序列化后仍然为原实例类型
     * 需要重新判断处理
     * @param obj
     * @return
     * @throws IOException
     */
    private Object handleRequest(Object obj) throws IOException {
        RpcRequest rpcRequest =(RpcRequest) obj;
        if(rpcRequest.getHeartBeat()){
            //如果是心跳包，不需要另外处理
            return rpcRequest;
        }
        Class<?>[] paramTypes = rpcRequest.getParamTypes();
        Object[] parameters = rpcRequest.getParameters();
        //判断parameters和 paramTypes是否一一对应
        for(int i=0;i<parameters.length; ++i){
            if(!paramTypes[i].isAssignableFrom(parameters[i].getClass())){
                //如果类型不匹配，重新序列化成byte数组，再按指定类型反序列化
                byte[] bytes = objectMapper.writeValueAsBytes(parameters[i]);
                parameters[i] = objectMapper.readValue(bytes,paramTypes[i]);
            }
        }
        return rpcRequest;
    }
}
